03/11 Archivos binarios. Pickles. Apareo de archivos secuenciales. CLASE DE LABORATORIO (Gonzalo)

with

Por lo general, cuando se trabaja con un archivo se hacen tres operaciones seguidas:

  1. Abrir el archivo
  2. Procesar el archivo
  3. Cerrar el archivo

Y hay que tener cuidado, porque si ocurre algún error con el archivo en algún punto de su procesamiento es necesario encargarse de cerrarlo, antes de que la excepción siga subiendo niveles. Para trabajar con los archivos de una forma más simple es que se agregó la sentencia with:


In [ ]:
with open('ejemplo.txt') as archivo:
    for linea in archivo:
        longitud = len(linea[:-1])
        print '%2d: %s' % (longitud, linea[:-1])

Si se fijan, no hay ningún close en esa porción de código, pero sin embargo al salir del bloque que encierra el with, el archivo se encuentra cerrado sin importar si salió exitosamente o con una excepción

Pickles

Los pickles son una forma de guardar estructuras de datos complejas y recuperarlas fácilmente, sin necesidad de convertirlas a texto y luego parsearlas:

Ejemplo 1: Guardar de a un elemento


In [ ]:
import pickle  # Importo la biblioteca necesaria

# Creo la variable archivo
with open('ejemplo.pkl', 'wb') as archivo:
    pkl = pickle.Pickler(archivo)  # Creo mi punto de acceso a los datos a partir del archivo

    lista1 = [1, 2, 3]
    lista2 = [4, 5]
    diccionario = {'campo1': 1, 'campo2': 'dos'}

    pkl.dump(lista1)         # Guardo la lista1 de [1, 2, 3]
    pkl.dump(None)           # Guardo el valor None
    pkl.dump(lista2)
    pkl.dump('Hola mundo')
    pkl.dump(diccionario)
    pkl.dump(1)

Para leer de un archivo pickle no puedo usar el método readline que usa la estructura for, por lo que no me queda otra que siempre intentar leer y cuando lance una excepción del tipo EOFError dejar de hacerlo.


In [ ]:
with open('ejemplo.pkl', 'rb') as archivo:
    seguir_leyendo = True
    while seguir_leyendo:
        try:
            data = pickle.load(archivo)  # Leo del archivo un elemento
        except EOFError:
            seguir_leyendo = False
        else:
            print '### Esta línea no es del archivo ###'
            print data

Ejemplo 2: Guardo una lista de elementos

Así como guardo de a un elemento por vez, también puedo guardar una lista que tenga todos los elementos que tenga en memoria:


In [ ]:
lista = [  # Creo la lista que quiero guardar
    {'usuario': 'usuario1', 'puntaje': 5}, 
    {'usuario': 'usuario2', 'puntaje': 3}, 
    {'usuario': 'usuario3', 'puntaje': 1}, 
]

# Guardo la lista en el archivo
with open('ejemplo_2.pkl', 'wb') as archivo:
    pkl = pickle.Pickler(archivo)
    pkl.dump(lista)

# Leo del archivo
with open('ejemplo_2.pkl', 'rb') as archivo:
    data = pickle.load(archivo)
    print data  # y muestro su contenido

Ejercicios

  1. Suponiendo que existe un archivo llamado utils.py donde se encuentran las funciones:
def guardar_en_archivo(archivo, contenido):
    """Guarda lo que le pasen como segundo parámetro en el archivo que
    recibe como primer parámetro.
    archivo tiene que estar abieto en modo binario y para escritura (wb)
    """
    ...


def leer_desde_archivo(archivo):
    """Lee del archivo archivo un registro y lo retorna junto con una
    variable booleana que indica si llegó al fin de archivo o no.
    archivo tiene que estar abieto en modo binario y para lectura (rb)
    """
    ...
    return data, fin_de_archivo

Leer dos archivos (61_matematica.dat y 75_computacion.dat) que tendrán registros con los campos:

* padron
* nombre
* apellido
* nota
* codigo_departamento
* codigo_materia

y armar uno nuevo donde sólo figuren las notas de los alumnos aprobados ordenados por padrón.
Ambos archivos están ordenados por padrón y se deben leer una única vez. Como los archivos pueden ser muy grandes, no se pueden guardar en memoria.
Una vez procesados los dos archivos se tienen que informar, para cada materia, cuántos alumnos aprobaron y cuántos desaprobaron.


In [ ]: